package com.zhangxx.web.common.aspect;

import cn.hutool.core.lang.UUID;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSONObject;
import com.zhangxx.web.common.annotation.LogFilter;
import com.zhangxx.web.model.MongoMsg;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/** 功能描述 : 日志切点
 *  对加了LogAspect的接口加入日志 记录入参出参  TODO 入参结果分离
  * @author zhangbo
  * @date 2019-08-26
  *
*/
@Aspect
@Component
@Order(120)
public class LogAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class) ;

   // @Resource
    //private MongoTemplate mongoTemplate;

    @Pointcut("@annotation(com.zhangxx.web.common.annotation.LogFilter)")
    public void logPointCut (){

    }
    @Around("logPointCut()")
    public Object around (ProceedingJoinPoint point) throws Throwable {
        Object result = null ;
        //请求时间
        Long startTime =System.currentTimeMillis();
        try{
            // 执行方法
            result = point.proceed();
            //处理时间
            Long doTime =System.currentTimeMillis()- startTime;

            // 保存请求日志
            saveRequestLog(point,result,doTime);
        } catch (Exception e){
            // 保存异常日志
            Long doTime = startTime-System.currentTimeMillis();
            saveExceptionLog(point,e.getMessage());
        }
        return result;
    }
    private void saveExceptionLog (ProceedingJoinPoint point,String exeMsg){
        LOGGER.info("捕获异常:"+exeMsg);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        LOGGER.info("请求路径:"+request.getRequestURL());
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        LOGGER.info("请求方法:"+method.getName());
        // 获取方法上LogFilter注解
        LogFilter logFilter = method.getAnnotation(LogFilter.class);
        String value = logFilter.value() ;
        LOGGER.info("模块描述:"+value);
        Object[] args = point.getArgs();
        LOGGER.info("请求参数:"+ JSONObject.toJSONString(args));

    }
    private void saveRequestLog (ProceedingJoinPoint point,Object result,Long time){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        // 记录请求参数
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        map.put("URL", request.getRequestURL().toString());
        map.put("HTTP_METHOD", request.getMethod());
        map.put("IP", ServletUtil.getClientIP(request));
        map.put("CLASS_METHOD", signature.getDeclaringTypeName() + "." + signature.getName());

        Map<String, String> headerMap = new LinkedHashMap<String, String>();
        // 获取用户appkey
        headerMap.put("appkey", request.getHeader("appkey"));
        // 发起请求时的时间戳（单位：毫秒）,13位
        headerMap.put("timestamp", request.getHeader("timestamp"));
        // 签名
        headerMap.put("sign", request.getHeader("sign"));
        // 随机数，用于放置重放攻击，注意避免重复【10位随机数】
        headerMap.put("nonce", request.getHeader("nonce"));
        map.put("requestHeader", headerMap);
        map.put("Params", getParamMap(request));
        // 获取方法上LogFilter注解
        LogFilter logFilter = method.getAnnotation(LogFilter.class);
        String value = logFilter.value() ;
        String collectionName = logFilter.name() ;
        //方法描述
        map.put("MethodDesc",value);
        //返回结果
        map.put("Return",result);
        map.put("ReturnTime(ms)",time);
        MongoMsg mongoMsg = new MongoMsg();
        mongoMsg.setId(UUID.fastUUID().toString(true));
        mongoMsg.setMsg(map);
        mongoMsg.setCreatTime(new Date(System.currentTimeMillis()));
        mongoMsg.setIp(ServletUtil.getClientIP(request));

        Object[] args = point.getArgs();
        LOGGER.info("请求参数:"+ JSONObject.toJSONString(args));

        //保存到mongoDb
       // mongoTemplate.save(mongoMsg, collectionName);
    }

    private Map<String, String> getParamMap(HttpServletRequest httpServletRequest) {
        Map<String, String> paramMap = new HashMap<>();
        for (Map.Entry<String, String[]> e : httpServletRequest.getParameterMap().entrySet()) {
            String params = "";
            String seq = "";
            for (int i = 0; i < e.getValue().length; i++) {
                params += seq + e.getValue()[i];
                seq = ",";
            }
            paramMap.put(e.getKey(), params);
        }
        return paramMap;
    }
}